﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NewLife;
using NewLife.Log;
using AppStart.Models;
using System.Diagnostics;
using System.Threading.Tasks;
using System.IO;
using System.Threading;

namespace AppStart.Common
{
    /// <summary>应用服务管理</summary>
    public class ServiceManager : DisposeBase
    {
        #region 属性
        public ServiceInfo[] Services { get; set; }

        private readonly List<Process> _processes = new List<Process>();
        #endregion

        #region 构造
        protected override void Dispose(Boolean disposing)
        {
            base.Dispose(disposing);

            Stop(disposing ? "Dispose" : "GC");
        }
        #endregion

        #region 方法
        public void Start()
        {
            var ts = new List<Task<Process>>();
            foreach (var item in Services)
            {
                if (item.AutoStart)
                {
                    Task.Factory.StartNew(() =>
                    {
                        var p = StartService(item);
                        if (p != null)
                            _processes.Add(p);
                    });
                };
            }
            Task.WaitAll(ts.ToArray());
            // 等待全部完成
            //var ps = Task.Factory.ContinueWhenAll(ts).Result;
            //_processes.AddRange(ps.Where(e => e != null));
        }

        private Process StartService(ServiceInfo service)
        {
            WriteLog("启动应用[{0}]：{1} {2}", service.Name, service.FileName, service.Arguments);

            // 修正路径
            var workDir = "";
            var file = service.FileName;
            if (file.Contains("/") || file.Contains("\\"))
            {
                file = file.GetFullPath();
                workDir = Path.GetDirectoryName(file);
            }
            else
            {
                workDir = AppDomain.CurrentDomain.BaseDirectory;
                file = Path.Combine(workDir, file);
            }

            var si = new ProcessStartInfo
            {
                FileName = file,
                Arguments = service.Arguments,
                WorkingDirectory = workDir,
            };
            if (file.ToLower().EndsWith(".dll"))
            {
                si.FileName = "dotnet";
                si.Arguments = " " + file + " " + service.Arguments;
            }
            var retry = service.Retry;
            if (retry <= 0) retry = 1024;
            for (var i = 0; i < retry; i++)
            {
                try
                {
                    var p = Process.Start(si);

                    WriteLog("应用[{0}]启动成功 PID={1}", service.Name, p.Id);

                    return p;
                }
                catch (Exception ex)
                {
                    Log?.Write(LogLevel.Error, "{0}", ex);

                    Thread.Sleep(5_000);
                }
            }

            return null;
        }

        public void Stop(String reason)
        {
            foreach (var item in _processes)
            {
                WriteLog("停止应用[{0}] PID={1} {2}", item.ProcessName, item.Id, reason);

                item.Kill();
            }
            _processes.Clear();
        }
        #endregion

        #region 日志
        public ILog Log { get; set; }

        public void WriteLog(String format, params Object[] args)
        {
            if (Log != null)
                Log.Info(format, args);
            else
                XTrace.WriteLine(format, args);
        }
        #endregion
    }
}
